﻿//*** Guidance generated code ***//
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web;

using ProjectBase.Core;

namespace $safeprojectname$
{
    /// <summary>
    ///     http://www.west-wind.com/weblog/posts/2012/Apr/02/Creating-a-JSONP-Formatter-for-ASPNET-Web-API
    ///     https://github.com/RickStrahl/AspNetWebApiArticle/blob/master/AspNetWebApi/Code/WebApi/Formatters/JsonpFormatter.cs
    ///     Handles JsonP requests when requests are fired with text/javascript
    /// </summary>
    public class JsonpFormatter : JsonMediaTypeFormatter
    {
        #region constructor
        public JsonpFormatter()
        {
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript"));

            JsonpParameterNames = new[] { "callback", "jsonp" };
        }
        #endregion constructor

        #region override public

        /// <summary>
        ///     Override this method to capture the Request object
        /// </summary>
        /// <param name="type"></param>
        /// <param name="request"></param>
        /// <param name="mediaType"></param>
        /// <returns></returns>
        public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType)
        {
            // each Api Service gets its own instance inside the Configuration
            JsonpCallbackFunction = GetJsonCallbackFunction(request);
            return this;

            //var formatter = new JsonpFormatter
            //{
            //    _jsonpCallbackFunction = GetJsonCallbackFunction(request)
            //};

            //// this doesn't work unfortunately
            ////formatter.SerializerSettings = GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings;

            //// You have to reapply any JSON.NET default serializer Customizations here
            ////formatter.SerializerSettings.Converters.Add(new StringEnumConverter());
            //formatter.SerializerSettings.Formatting = Formatting.Indented;

            //return formatter;
        }


        public override Task WriteToStreamAsync(Type type, object value, Stream stream
            , HttpContent content, TransportContext transportContext)
        {
            if (string.IsNullOrEmpty(JsonpCallbackFunction))
            {
                return base.WriteToStreamAsync(type, value, stream, content, transportContext);
            }

            StreamWriter writer = null;

            // write the pre-amble
            try
            {
                writer = new StreamWriter(stream);
                writer.Write(JsonpCallbackFunction + "(");
                writer.Flush();
            }
            catch (Exception ex)
            {
                try
                {
                    if (writer != null)
                    {
                        writer.Dispose();
                    }
                }
                catch { }

                var tcs = new TaskCompletionSource<object>();
                tcs.SetException(ex);
                return tcs.Task;
            }

            return base.WriteToStreamAsync(type, value, stream, content, transportContext)
                       .ContinueWith(innerTask =>
                       {
                           if (innerTask.Status == TaskStatus.RanToCompletion)
                           {
                               writer.Write(")");
                               writer.Flush();
                           }
                           writer.Dispose();
                           return innerTask;
                       }, TaskContinuationOptions.ExecuteSynchronously)
                       .Unwrap();
        }

        //public override bool CanWriteType(Type type)
        //{
        //    return true;
        //}
        #endregion override public

        /// <summary>
        ///     Retrieves the Jsonp Callback function
        ///     from the query string
        /// </summary>
        /// <returns></returns>
        protected virtual string GetJsonCallbackFunction(HttpRequestMessage request)
        {
            if (request.Method != HttpMethod.Get)
            {
                return null;
            }

            NameValueCollection query = HttpUtility.ParseQueryString(request.RequestUri.Query);
            foreach (var name in JsonpParameterNames)
            {
                string queryVal = query[name];

                if (queryVal.Is())
                {
                    return queryVal;
                }
            }

            return null;
        }

        #region properties
        /// <summary>
        ///     Captured name of the Jsonp function that the JSON call
        ///     is wrapped in. Set in GetPerRequestFormatter Instance
        /// </summary>
        protected string JsonpCallbackFunction { get; set; }
        /// <summary>
        ///     Name of the query string parameter to look for
        ///     the jsonp function name
        /// </summary>
        protected IList<string> JsonpParameterNames { get; set; }
        #endregion
    }
}